
// 该文件对应于守护进程中的共享内存检查定时器的机制
// 如启用共享内存sequence检查，应该在worker进程中集成如下类似代码
// worker进程不用感知守护进程，共享内存不存在也不会导致worker工作不正常

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>
#include <string>
#include <thread>
#include "heartbeat.h"
#include "loghelper.h"
#include "utility.hpp"
using namespace RockLog;
using namespace boost::interprocess;

static int openShm(shared_memory_object &shm, const std::string &workerId)
{
    try
    {
        // Open already created shared memory object.
        shm = std::move(shared_memory_object(open_only, workerId.c_str(), read_write));
        return 0;
    }
    catch (std::exception &e)
    {
        LOG(kErr) << "open shared memory: " << workerId << " failed!, exception: " << e.what() << "\n";
        return -1;
    }
}

void startHeartBeat(const std::string &workerId)
{
    std::thread([&]() {
        try
        {
            uint64_t sequence = 0;
            LOG(kDebug) << "[startHeartBeat] workerId: " << workerId;
            while (true)
            {
                // Open already created shared memory object.
                shared_memory_object shm;

                while (true)
                {
                    if (0 != openShm(shm, workerId))
                    {
                        Utility::sleep(1);
                        openShm(shm, workerId);
                    }
                    else
                    {
                        break;  
                    }
                }

                // Map the whole shared memory in this process
                mapped_region region(shm, read_write);

                // clear the memory for worker process, the other half memory is for daemon process
                std::memset(region.get_address(), 0, region.get_size() / 2);

                sequence += 1;
                std::copy((char *)&sequence, (char *)&sequence + sizeof(sequence), (char *)region.get_address());

                LOG(kDebug) << "[startHeartBeat] workerId:" << workerId << "current heartbeat sequence is:" << sequence;

                Utility::sleep(1); // write every 1 second
            }
        }
        catch (std::exception &e)
        {
            LOG(kErr) << "workerId: "<< workerId << "startHeartBeat failed, exception: " << e.what() << "\n";
        }
    }).detach();
}